﻿using PSL.Lexer;
using PSL.ST;
using PSL.Stack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PSL
{
    public class PSLRuntime
    {
        #region Private Member
        private PSLEngine runtime;
        private FunctionStack functionStack;
        private VariableStack variableStack;
        #endregion

        #region Constructor
        /// <summary>
        /// Create new PrivateScriptLanguage engine, which manage the complete scripting enviroment
        /// </summary>
        public PSLRuntime()
        {
            functionStack = new FunctionStack(this);
            variableStack = new VariableStack(this);
            runtime = new PSLEngine(this);
        }
        #endregion

        #region Private Methods

        #endregion

        #region Public Methods
        /// <summary>
        /// Execute Script-Part
        /// </summary>
        /// <param name="Script">Script</param>
        public void Execute(string Script)
        {
            // Create tokenizer
            Tokenizer tokenizer = new Tokenizer();
            tokenizer.Parse(Script);

            // Create the parser
            Parser parser = new Parser();

            // Parse the script into a syntax-tree
            parser.Parse(tokenizer.Tokens);
            SyntaxTree completeTree = parser.SyntaxTree; 

            // Split the syntax-tree            
            SyntaxTreeParser stParser = new SyntaxTreeParser(completeTree);
            SyntaxTree functionTree = stParser.GetFunctionDeclarations();
            SyntaxTree executeTree = stParser.GetSyntaxTreeToExecute();
            
            // Load functions, so then they can be used before declaration
            functionStack.LoadFunctions(functionTree);

            // Execute the execute-tree
            runtime.Execute(executeTree);
        }

        /// <summary>
        /// Load Script from the file-system
        /// </summary>
        /// <param name="Path"></param>
        public void LoadeScript(string Path)
        {
            // Load script and execute
            Execute(System.IO.File.ReadAllText(Path));
        }

        /// <summary>
        /// Add Method to the system
        /// </summary>
        /// <param name="Name">Name of the method</param>
        /// <param name="Method">method-delegate</param>
        public void AddMethod(string Name, Delegate Method)
        {
            functionStack.AddFunction(Name, Method);
        }

        /// <summary>
        /// Add a variable to the system
        /// </summary>
        /// <param name="Name">Name of the variable</param>
        /// <param name="Value">Default value</param>
        public void AddVairable(string Name, dynamic Value)
        { 
            
        }
        #endregion

        #region Public Member
        /// <summary>
        /// Global function-stack
        /// </summary>
        public FunctionStack FunctionStack
        {
            get { return functionStack; }
        }

        /// <summary>
        /// Global variable stack
        /// </summary>
        public VariableStack VariableStack
        {
            get { return variableStack; }
        }

        /// <summary>
        /// Runtime of the current engine
        /// </summary>
        public PSLEngine Runtime
        {
            get { return runtime; }
        }
        #endregion
    }
}
